<?php

namespace App\Http\Controllers;

use Encore\Admin\Controllers\HasResourceActions;
use App\Models\PayLog;
use App\Models\Client;
use App\Models\AdminUser;
use App\Models\ChargeOrder;
use Encore\Admin\Facades\Admin;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Request;
use App\Http\Controllers\Controller;
use EasyWeChat\Factory;
use SimpleSoftwareIO\QrCode\Facades\QrCode;
use GuzzleHttp\Client as GuzzleClient;
use GuzzleHttp\Exception\RequestException;

class PaymentController extends Controller
{
    // 请求微信接口的公用配置, 所以单独提出来
    private function payment()
    {
        $config = [
            // 必要配置, 这些都是之前在 .env 里配置好的
            'app_id' => config('wechat.payment.default.app_id'),
            'mch_id' => config('wechat.payment.default.mch_id'),
            'key' => config('wechat.payment.default.key'),   // API 密钥
            'notify_url' => config('wechat.payment.default.notify_url'),   // 通知地址
        ];
        // 这个就是 easywechat 封装的了, 一行代码搞定, 照着写就行了
        $app = Factory::payment($config);
        $app->setSubMerchant(config('wechat.payment.default.submch_id'), config('wechat.payment.default.subapp_id'));

        return $app;
    }

    public function place_order()
    {
        $request = Request::all();
        $client_url = $request['client_url'];
        $post_price = $request['post_price'];
        $pay_price = env('APP_DEBUG') ? 1 : floatval($post_price) * 100;
        $pay_log = PayLog::where('client_url', $client_url)->where('status', 0)->where('pay_type', 41)->first();
        if (count($pay_log)) {
            $order_sn = $pay_log->out_trade_no;
            $pay_log->post_price = $post_price;//更新提交的价格
            $pay_log->save();
        } else {
            $order_sn = date('ymd') . substr(time(), -5) . substr(microtime(), 2, 5);//订单号
            $client_id = Client::where('client_url', $client_url)->value('id');
            if (!$client_id) return ['code' => 202, 'msg' => '用户不存在'];
            // 创建 Paylog 记录
            Db::table('pay_logs')->insert([
                'appid' => config('wechat.payment.default.app_id'),
                'out_trade_no' => $order_sn,
                'post_price' => $post_price,
                'pay_type' => 41,//微信
                'order_at' => time(),
                'client_id' => $client_id,
                'client_url' => $client_url,
                'mch_id' => config('wechat.payment.default.mch_id'),
            ]);
        }
        //写入客户的数据库
        $pay_data = [
            'form_params' => [     //参数组
                'out_trade_no' => $order_sn,
                'post_price' => $post_price,
                'pay_type' => 41,//微信
                'order_at' => time(),
                'appid' => config('wechat.payment.default.app_id'),
                'mch_id' => config('wechat.payment.default.mch_id'),
            ],
        ];
        try {
            $send_url = "http://{$client_url}/api/payment/paylog";
            $this->guzzle($send_url, $pay_data);
        } catch (RequestException $e) {
            file_put_contents('../storage/logs/pay_log.txt', '|'.$client_url.':'.$e->getRequest(), FILE_APPEND);
            return json_encode(['code' => 202, 'title' => '写入用户充值记录失败']);
        }

        $app = $this->payment();
        // 用 easywechat 封装的方法请求微信的统一下单接口
        $result = $app->order->unify([
            'trade_type' => 'NATIVE', // 原生支付即扫码支付，商户根据微信支付协议格式生成的二维码，用户通过微信“扫一扫”扫描二维码后即进入付款确认界面，输入密码即完成支付。
            'body' => '微信支付', // 这个就是会展示在用户手机上巨款界面的一句话, 随便写的
            'out_trade_no' => $order_sn,
            'total_fee' => $pay_price,
        ]);

        if ($result['result_code'] == 'SUCCESS') {
            // 如果请求成功, 微信会返回一个 'code_url' 用于生成二维码
            $code_url = $result['code_url'];
            return json_encode([
                'code' => 200,
                // 订单编号, 用于在当前页面向微信服务器发起订单状态查询请求
                'title' => '微信充值',
                'money' => $pay_price.'元',
                'order_sn' => $order_sn,
                // 生成二维码
                'html' => QrCode::size(200)->generate($code_url),
            ]);
        }else{
            return json_encode($request);
        }
    }

    //异步回调
    public function notify(){
        $app = $this->payment();
        // 用 easywechat 封装的方法接收微信的信息, 根据 $message 的内容进行处理, 之后要告知微信服务器处理好了, 否则微信会一直请求这个 url, 发送信息
        $response = $app->handlePaidNotify(function($message, $fail){
            $payLog = PayLog::where('out_trade_no',  $message['out_trade_no'])->first();
            if (!$payLog || $payLog->paid_at) { // 如果订单不存在 或者 订单已经支付过了
                return true; // 告诉微信，我已经处理完了，订单没找到，别再通知我了
            }
            // return_code 表示通信状态，不代表支付状态
            if ($message['return_code'] === 'SUCCESS') {
                // 用户是否支付成功
                if ($message['result_code'] === 'SUCCESS') {
                    // 更新 PayLog, 这里的字段都是根据微信支付结果通知的字段设置的(https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_7&index=8)
                    PayLog::where('out_trade_no', $message['out_trade_no'])->update([
                        'total_fee' => $message['total_fee']/100,
                        'trade_type' => '微信扫码',
                        'paid_at' => time(),
                        'transaction_id' => $message['transaction_id'],
                        'status' => 1,//充值成功
                        'result_code' => $message['result_code'],
                        'bank_type' => $message['bank_type'],
                        'mch_id' => $message['mch_id'],
                        'openid' => $message['openid'],
                    ]);
                    //用户帐户余额增加
                    Db::update('update clients set cash=cash + ' . $message['total_fee']/100 . ' where id = ?', [$payLog->client_id]);
                    file_put_contents('../storage/logs/update_cash.txt', '|用户client_id:'.$payLog->client_id.'-type:微信-时间：'.date('Y-m-d H:i:s').'-金额：'.$message['total_fee']/100, FILE_APPEND);
                    //发送数据给客户的服务器进行保存,改变状态
                    $pay_data = [
                        'form_params' => [        //参数组
                            'out_trade_no' => $message['out_trade_no'],
                            'status' => 1,//充值成功
                            'total_fee' => $message['total_fee']/100,
                            'trade_type' => '微信扫码',
                            'paid_at' => time(),
                            'transaction_id' => $message['transaction_id'],
                            'result_code' => $message['result_code'],
                        ],
                    ];

                    try {
                        $send_url = "http://{$payLog->client_url}/api/payment/state";
                        $this->guzzle($send_url, $pay_data);
                    } catch (RequestException $e) {
                        file_put_contents('../storage/logs/pay_log.txt', '|' . $send_url . ':' . $e->getRequest(), FILE_APPEND);
                    }
                }
            } else {
                // 如果支付失败, 也更新 PayLog, 跟上面一样, 就是多了 error 信息
                PayLog::where('out_trade_no', $message['out_trade_no'])->update([
                    'total_fee' => $message['total_fee']/100,
                    'trade_type' => '微信扫码',
                    'paid_at' => time(),
                    'transaction_id' => $message['transaction_id'],
                    'status' => 2,//充值成功
                    'result_code' => $message['result_code'],
                    'bank_type' => $message['bank_type'],
                    'mch_id' => $message['mch_id'],
                    'openid' => $message['openid'],
                    'result_code' => $message['result_code'],
                    'return_code' => $message['return_code'],
                ]);
                //发送数据给客户的服务器进行保存,改变状态
                $pay_data = [
                    'form_params' => [        //参数组
                        'out_trade_no' => $message['out_trade_no'],
                        'status' => 2,//充值成功
                        'total_fee' => $message['total_fee']/100,
                        'trade_type' => '微信扫码',
                        'paid_at' => time(),
                        'transaction_id' => $message['transaction_id'],
                        'result_code' => $message['result_code'],
                    ],
                ];
                try {
                    $send_url = "http://{$payLog->client_url}/api/payment/state";
                    $this->guzzle($send_url, $pay_data);
                } catch (RequestException $e) {
                    file_put_contents('../storage/logs/pay_log.txt', '|' . $send_url . ':' . $e->getRequest(), FILE_APPEND);
                }
                return $fail('通信失败，请稍后再通知我');
            }
            return true; // 返回处理完成
        });
        // 这里是必须这样返回的, 会发送给微信服务器处理结果
        return $response;
    }

    public function guzzle($url, $params)
    {
        $client = new GuzzleClient([
            // 超时
            'timeout' => 5.0,
        ]);
        return $client->request('POST', $url, $params);
    }

    //请求订单的状态
    public function paid()
    {
        $out_trade_no = Request::get('out_trade_no');

        $app = $this->payment();
        // 用 easywechat 封装的方法请求微信
        $result = $app->order->queryByOutTradeNumber($out_trade_no);

        if ($result['trade_state'] === 'SUCCESS'){
            return json_encode([
                'code' => 200,
                'msg' => 'paid'
            ]);
        }else{
            return json_encode([
                'code' => 202,
                'msg' => 'not paid'
            ]);
        }
    }
}